package com.pithypan.service.impl;

import com.pithypan.common.Constants;
import com.pithypan.common.ResponseCodeEnum;
import com.pithypan.common.UserStatusEnums;
import com.pithypan.common.exceptionHandler.MyException;
import com.pithypan.common.utils.R;
import com.pithypan.common.utils.RedisUtils;
import com.pithypan.common.utils.StringTools;
import com.pithypan.dto.SessionWebUserDto;
import com.pithypan.dto.SysSettingsDto;
import com.pithypan.dto.UserSpaceDto;
import com.pithypan.entity.UserInfo;
import com.pithypan.mapper.FileInfoMapper;
import com.pithypan.mapper.UserInfoMapper;
import com.pithypan.service.EmailCodeService;
import com.pithypan.service.UserInfoService;
import com.pithypan.vo.PaginationResultVo;
import com.pithypan.vo.UserInfoQuery;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;

/**
 * <p>
 * 用户信息 服务实现类
 * </p>
 *
 * @author author
 * @since 2023-08-17
 */
@Service
@Transactional
public class UserInfoServiceImpl implements UserInfoService {

    @Resource
    private EmailCodeService emailCodeService;
    @Resource
    private UserInfoMapper userInfoMapper;
    @Resource
    private RedisUtils redisUtils;
    @Resource
    private FileInfoMapper fileInfoMapper;

    @Value("${admin.emails}")
    private String adminEmails;         //加载配置中的管理员账号


    /**
     * 用户分页查询
     * @param query
     * @return
     */
    @Override
    public PaginationResultVo findListByPage(UserInfoQuery query) {
        PaginationResultVo resultVo = new PaginationResultVo();
        resultVo.setPageSize(query.getPageSize());      //每页显示数据项数
        resultVo.setPageNo(query.getPageNo());          //页码

        //计算总记录数
        Integer totalCount = userInfoMapper.findTotalCount(query);
        resultVo.setTotalCount(totalCount);

        //查询数据集
        int start = (query.getPageNo() - 1) * query.getPageSize();  //计算起始位置
        query.setStart(start);
        ArrayList<UserInfo> list = userInfoMapper.findListByPage(query);
        resultVo.setList(list);

        //计算总页数
        int pageTotal = totalCount % query.getPageSize() == 0 ?
                totalCount /query.getPageSize() : (totalCount / query.getPageSize()) + 1;
        resultVo.setPageTotal(pageTotal);

        return resultVo;
    }


    /**
     * 用户注册
     * @param userInfo    注册信息（注册邮箱、用户名、用户密码）
     * @param emailCode   用户提交的邮箱验证码
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void register(UserInfo userInfo, String emailCode) {
        UserInfo user = userInfoMapper.selectByEmail(userInfo.getEmail());
        if (user != null) {
            throw new MyException(ResponseCodeEnum.CODE_404.getCode(), ResponseCodeEnum.CODE_404.getMsg());
        }
        user = userInfoMapper.selectByNickName(userInfo.getNickName());
        if (user != null) {
            throw new MyException(690, "昵称已存在");
        }

        //校验邮箱验证码
        emailCodeService.checkCode(userInfo.getEmail(), emailCode);

        String userId = StringTools.getRandomNumber(10);   //生成id
        userInfo.setUserId(userId);            //设置用户id
        String password = userInfo.getPassword();
        userInfo.setPassword(StringTools.encodeByMd5(password));   //设置用户密码（Md5加密）
        userInfo.setJoinTime(new Date());      //设置用户注册日期
        userInfo.setStatus(1);                 //设置用户为启用状态
        userInfo.setUseSpace(0L);              //设置用户已使用空间 单位/byte
        //设置用户总空间/MB
        //先从redis缓存中获取邮件模板
        SysSettingsDto sysSettingsDto = (SysSettingsDto) redisUtils.get(Constants.REDIS_KEY_SYS_SETTING);
        //缓存中没有邮件，则根据默认模版创建一封邮件并存入redis中
        if (sysSettingsDto == null) {
            sysSettingsDto = new SysSettingsDto();
            redisUtils.set(Constants.REDIS_KEY_SYS_SETTING, sysSettingsDto);
        }
        userInfo.setTotalSpace(sysSettingsDto.getUserInitUserSpace() * 1024 * 1024L); //设置用户总空间/MB

        userInfoMapper.insert(userInfo);    //用户存入数据库
    }


    /**
     * 用户登录
     * @param email        邮箱账号
     * @param password     加密后的密码
     * @return
     */
    @Override
    public SessionWebUserDto login(String email, String password) {
        UserInfo userInfo = userInfoMapper.selectByEmail(email);
        if (userInfo == null || !userInfo.getPassword().equals(password)) {
            throw new MyException(504, "账号或密码错误");
        }
        if (userInfo.getStatus() == 0) {
            throw new MyException(507, "账号已禁用，请联系客服");
        }

        UserInfo updateInfo = new UserInfo();
        updateInfo.setLastLoginTime(new Date());     //设置最后一次登陆时间
        userInfoMapper.updateByUserId(updateInfo, userInfo.getUserId()); //更新用户的最后一次登陆时间

        //生成登陆用户信息
        SessionWebUserDto sessionWebUserDto = new SessionWebUserDto();
        sessionWebUserDto.setUserId(userInfo.getUserId());
        sessionWebUserDto.setNickName(userInfo.getNickName());
        //判断是否为管理员账号
        //split：根据参数将字符串分割成数组   apache-->ArrayUtils.contains: 判断参数1中是否有参数2
        if (ArrayUtils.contains(adminEmails.split(","), email)) {
            sessionWebUserDto.setAdmin(true);
        } else {
            sessionWebUserDto.setAdmin(false);
        }

        //生成登陆用户的使用空间情况
        UserSpaceDto userSpaceDto = new UserSpaceDto();
        Long useSpace = fileInfoMapper.selectUseSpace(userInfo.getUserId());//查询当前用户已上传文件大小总和
        userSpaceDto.setUseSpace(useSpace);
        userSpaceDto.setTotalSpace(userInfo.getTotalSpace()); //设置用户可使用总空间
        redisUtils.set(Constants.REDIS_KEY_USER_SPACE_USE + userInfo.getUserId(), userSpaceDto); //redis缓存

        return sessionWebUserDto;
    }


    /**
     * 根据邮箱修改密码（用户未登陆，需要邮箱验证）
     * @param email        邮箱
     * @param password     新密码
     * @param emailCode    邮箱验证码
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void resetPwd(String email, String password, String emailCode) {
        UserInfo userInfo = userInfoMapper.selectByEmail(email);
        if (userInfo == null) {
            throw new MyException(404, "邮箱账号不存在");
        }
        emailCodeService.checkCode(email, emailCode);   //校验邮箱验证码

        UserInfo updateInfo = new UserInfo();
        updateInfo.setPassword(StringTools.encodeByMd5(password));
        userInfoMapper.updatePasswordByEmail(updateInfo, email);  //更新密码
    }


    /**
     * 根据userId修改用户头像
     * @param updateInfo
     * @param userId
     */
    @Override
    public void updateUserAvatarByUserId(UserInfo updateInfo, String userId) {
        userInfoMapper.updateUserQqAvatarByUserId(updateInfo, userId);
    }


    /**
     * 根据userId修改密码
     * @param updateInfo
     * @param userId
     */
    @Override
    public void updatePasswordByUserId(UserInfo updateInfo, String userId) {
        userInfoMapper.updatePasswordByUserId(updateInfo, userId);
    }

    /**
     * 查询用户所有已上传文件大小总和
     * @param userId
     * @return
     */
    @Override
    public Long getUserSpace(String userId) {
        return fileInfoMapper.selectUseSpace(userId);  //查询当前用户已上传文件大小总和
    }


    /**
     * 根据用户id更改状态
     * @param userId
     * @param status
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUserStatus(String userId, Integer status) {
        UserInfo update = new UserInfo();
        update.setStatus(status);

        //如果是更改为禁用状态，则清空用户所上传的文件
        if (status.equals(UserStatusEnums.DISABLE.getStatus())) {
            update.setUseSpace(0L);
            fileInfoMapper.delFileByUserId(userId);   //删除该用户的所有文件
        }

        userInfoMapper.updateByUserId(update, userId);
    }


    /**
     * 修改用户可使用空间
     * @param userId
     * @param changeSpace
     */
    @Override
    public void changeUserSpace(String userId, Long changeSpace) {
        //更新数据库
        Long space = changeSpace * 1024 * 1024L;   //转化为MB
        this.userInfoMapper.updateUserSpace(userId, null, space);

        UserSpaceDto spaceDto = (UserSpaceDto) redisUtils.get(Constants.REDIS_KEY_USER_SPACE_USE + userId);
        if (spaceDto != null) {
            spaceDto.setTotalSpace(space);
            //更新redis
            redisUtils.set(Constants.REDIS_KEY_USER_SPACE_USE + userId, spaceDto);
        }
    }


    /**
     * 根据id获得用户
     * @param userId
     * @return
     */
    @Override
    public UserInfo getUserInfoByUserId(String userId) {
        return this.userInfoMapper.findUserInfoByUserId(userId);
    }
}
